package org.infohold.mysql.conf;

import java.util.Properties;

import javax.sql.DataSource;

import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.context.annotation.AdviceMode;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.interceptor.TransactionInterceptor;

import lombok.extern.slf4j.Slf4j;

@Configuration
@EnableTransactionManagement(mode = AdviceMode.PROXY, order = TxConstants.DEFAULT_TX_AOP_ORDER)
@AutoConfigureAfter(DruidAutoConfiguration.class)
@EnableAspectJAutoProxy(proxyTargetClass = true)
@MapperScan(basePackages = { "com.infohold.*.*.mapper" })
@PropertySource("classpath:db-config.properties")
@Slf4j
public class DatasourceConfig {

	@Autowired
	private DataSource dataSource;

	/**
	 * 数据库事务管理
	 *
	 * @return
	 */
	@Bean
	@Primary
	public PlatformTransactionManager transactionManager() {
		return new DataSourceTransactionManager(dataSource);
	}

	/**
	 * 事务拦截属性设置
	 *
	 * @return
	 */
	@Bean
	public Properties txInterceptorProperties() {
		Properties p = new Properties();
		// 默认只读（不符合开发规范的写操作一律屏蔽掉）
		p.setProperty(TxConstants.FUNC_PREFIX_ALL, TxConstants.READ_ONLY);

		// 写操作事务级别
		for (String prefix : TxConstants.TX_WRITE_FUNC_LIST) {
			if (StringUtils.isBlank(prefix)) {
				continue;
			}
			p.setProperty(prefix, TxConstants.LEVEL_PROPAGATION_REQUIRED);
		}

		// 读操作事务级别
		for (String prefix : TxConstants.READ_FUNC_LIST) {
			if (StringUtils.isBlank(prefix)) {
				continue;
			}
			p.setProperty(prefix, TxConstants.LEVEL_PROPAGATION_SUPPORTS);
		}
		return p;
	}

	/**
	 * 事务切面设置
	 *
	 * @param txManager
	 * @param txInterceptorProperties
	 * @return
	 */
	@Bean
	@Primary
	public Advisor jpaRepositoryAdvisor(PlatformTransactionManager txManager,
			@Qualifier("txInterceptorProperties") Properties txInterceptorProperties) {
		AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
		pointcut.setExpression(TxConstants.DEFAULT_TX_AOP_EXPRESSION);
		TransactionInterceptor txInterceptor = new TransactionInterceptor(txManager, txInterceptorProperties);
		txInterceptor.afterPropertiesSet();
		log.debug("Transaction Interceptor use Properties[{}].", txInterceptorProperties);
		DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(pointcut, txInterceptor);
		advisor.setOrder(TxConstants.DEFAULT_TX_AOP_ORDER);
		return advisor;
	}

	/**
	 * SQL会话工厂
	 * 
	 * @param dataSource
	 * @return
	 * @throws Exception SqlSessionFactory
	 */
	@Bean
	public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
		WildcardSqlSessionFactoryBean sessionFactory = new WildcardSqlSessionFactoryBean();
		sessionFactory.setDataSource(dataSource);
		sessionFactory.setConfigLocation(
				new PathMatchingResourcePatternResolver().getResources("classpath*:mybatis-config.xml")[0]);
		sessionFactory.setMapperLocations(
				new PathMatchingResourcePatternResolver().getResources("classpath*:mappers/**/*.xml"));
		sessionFactory.setTypeAliasesPackage("com.xfqb.**.entity");
		return sessionFactory.getObject();
	}
}
